#pragma once
#include<iostream>
#include<pthread.h>
#include<queue>
#include"mutex.hpp"

namespace ly{
    template<class T>
    class BlockQueue{
    public:
        BlockQueue(int size=10):_size(size){
            pthread_mutex_init(_mutex.get_mutex(), NULL);
            pthread_cond_init(&_consumer_cond, NULL);
            pthread_cond_init(&_producer_cond, NULL);
            _producer_wait_num=0;_consumer_wait_num=0;
            is_running=true;
        }
        void push(T data){
            _mutex.lock();
            while(_q.size()>=_size&&is_running){
                _producer_wait_num++;//生产者V操作
                pthread_cond_wait(&_producer_cond,_mutex.get_mutex());//阻塞生产者线程,自动释放锁
                _producer_wait_num--;//生产者P操作
            }
            if(!is_running){
                    _mutex.unlock();
                    return;
                }
            _q.push(data);
            std::cout<<"push data"<<std::endl;
            _mutex.unlock();
            pthread_cond_signal(&_consumer_cond);
        }
        // void push(T data=T()){
        //     ly::LockGuard Lock(mutex_);
        //     while(_q.size()>=_size){
        //         _producer_wait_num++;//生产者V操作
        //         pthread_cond_wait(&_producer_cond,&mutex_);//阻塞生产者线程,自动释放锁
        //         _producer_wait_num--;//生产者P操作
        //     }
        //     _q.push(data);
        //     pthread_cond_signal(&consumer_cond_);
        // }
        T pop(){
            _mutex.lock();
            while(_q.empty()&&is_running){
                _consumer_wait_num++;
                std::cout<<"consumer wait"<<std::endl;
                pthread_cond_wait(&_consumer_cond,_mutex.get_mutex());
                std::cout<<"consumer wakeup"<<std::endl;
                _consumer_wait_num--;
            }
            if((!is_running)&&_q.empty()){
                _mutex.unlock();
                return T();
            }
            T data=_q.front();
            _q.pop();
            std::cout<<"pop data"<<std::endl;
            pthread_cond_signal(&_producer_cond);
            _mutex.unlock();
            return data;
        }
        bool empty(){
            return _q.empty();
        }
        void set_size(int size=5){
            _size=size;
        }
        //唤醒全部等待线程
        void wake_all(){
            pthread_cond_broadcast(&_consumer_cond);
            pthread_cond_broadcast(&_producer_cond);
        }
        ~BlockQueue(){
            pthread_mutex_destroy(_mutex.get_mutex());
        }
        unsigned int GetConsumerWaitNum(){
            return _consumer_wait_num;
        }
        unsigned int GetProducerWaitNum(){
            return _producer_wait_num;
        }
        void set_running(bool running){
            is_running=running;
        }
    private:
        std::queue<T> _q;
        unsigned int _size,_consumer_wait_num, _producer_wait_num;
        ly::Mutex _mutex;
        bool is_running;
        pthread_cond_t _consumer_cond,_producer_cond;
    };
}